/*
 * Copyright (C) 2013 Michał Charmas (http://blog.charmas.pl)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package pl.charmas.parcelablegenerator;

import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import pl.charmas.parcelablegenerator.typeserializers.*;
import pl.charmas.parcelablegenerator.util.PsiUtils;
import pl.charmas.parcelablegenerator.util.SCAAnnotationUtil;

import java.util.List;


/**
 * 生成setOnClickListener
 */
public class ClickGenerator {
	private final PsiClass mClass;
	private final List<PsiField> mFields;
	private final TypeSerializerFactory mTypeSerializerFactory;

	public ClickGenerator(PsiClass psiClass, List<PsiField> fields) {
		mClass = psiClass;
		mFields = fields;

		this.mTypeSerializerFactory = new ChainSerializerFactory(new BundleSerializerFactory(), new DateSerializerFactory(), new EnumerationSerializerFactory(), new PrimitiveTypeSerializerFactory(), new PrimitiveArraySerializerFactory(), new ParcelableSerializerFactory(), new ListSerializerFactory(), new SerializableSerializerFactory());
	}


	private String getOnClickContents(List<PsiField> fields) {
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("@Override public void onClick(View v){");
		stringBuilder.append(" switch(v.getId()){ ");
		//TODO此处循环
		for (PsiField psiField : fields) {
			//			SCAAnnotationUtil.annotation.getQualifiedName()
			PsiAnnotation annotation = SCAAnnotationUtil.getAnnotation(psiField, SCAAnnotationUtil.TAINJECT_VIEW_ANNOTATION_CLASS);
			if (annotation != null) {
				String sa = getAttribute(annotation, "id", "0");
				stringBuilder.append("case " + sa + ":");
				stringBuilder.append("break;");
			}
		}
		stringBuilder.append("default:\nbreak;");
		stringBuilder.append("}");
		stringBuilder.append("}");
		return stringBuilder.toString();
	}

	public void generate() {
		PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(mClass.getProject());


		// Describe contents method
		PsiMethod onClickContentsMethod = elementFactory.createMethodFromText(getOnClickContents(mFields), mClass);

		PsiMethod initClickContentsMethod = elementFactory.createMethodFromText(getInitClickContents(mFields), mClass);

		// Default constructor if needed 生成末日的构造函数
		String defaultConstructorString = generateDefaultConstructor(mClass);


		JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(mClass.getProject());

		// Shorten all class references
		styleManager.shortenClassReferences(mClass.addBefore(initClickContentsMethod, mClass.getLastChild()));
		styleManager.shortenClassReferences(mClass.addBefore(onClickContentsMethod, mClass.getLastChild()));
		styleManager.optimizeImports(mClass.getContainingFile());
		GlobalSearchScope scope = GlobalSearchScope.allScope(mClass.getProject());
		PsiClass psiClass = JavaPsiFacade.getInstance(mClass.getProject()).findClass("android.widget.Button", scope);
		styleManager.addImport( (PsiJavaFile)mClass.getContainingFile(), psiClass);
		makeClassImplemenOnClickListener(elementFactory);//实现Parceable接口
	}

	private String getInitClickContents(List<PsiField> mFields) {
		StringBuilder sb = new StringBuilder();
		sb.append("public void initClickListener(){");
		for (PsiField psiField : mFields) {
			PsiAnnotation annotation = SCAAnnotationUtil.getAnnotation(psiField, SCAAnnotationUtil.TAINJECT_VIEW_ANNOTATION_CLASS);
			if (annotation != null) {
				String name = psiField.getName();
				sb.append(name + ".setOnClickListener(this);");
			}

		}
		sb.append("}");
		return sb.toString();
	}

	private boolean hasParcelableSuperclass() {
		PsiClassType[] superTypes = mClass.getSuperTypes();
		for (PsiClassType superType : superTypes) {
			if (PsiUtils.isOfType(superType, "android.os.Parcelable")) {
				return true;
			}
		}
		return false;
	}

	private static <T> T getAttribute(PsiAnnotation annotation, String field, @NotNull T defaultValue) {
		if (annotation == null) {
			return defaultValue;
		} else {
			PsiAnnotationMemberValue value = annotation.findAttributeValue(field);
			if (value instanceof PsiReferenceExpressionImpl) {
				return (T) ((PsiReferenceExpressionImpl) value).getQualifiedName();
			} else {
				return defaultValue;
			}
		}
	}


	private String generateDefaultConstructor(PsiClass clazz) {
		// Check for any constructors; if none exist, we'll make a default one
		if (clazz.getConstructors().length == 0) {
			// No constructors exist, make a default one for convenience
			return "public " + clazz.getName() + "(){}" + '\n';
		} else {
			return null;
		}
	}

	private void makeClassImplemenOnClickListener(PsiElementFactory elementFactory) {
		if (hasParcelableSuperclass())
			return;

		final PsiClassType[] implementsListTypes = mClass.getImplementsListTypes();
		final String implementsType = "android.view.View.OnClickListener";

		for (PsiClassType implementsListType : implementsListTypes) {
			PsiClass resolved = implementsListType.resolve();

			// Already implements Parcelable, no need to add it
			if (resolved != null && implementsType.equals(resolved.getQualifiedName())) {
				return;
			}
		}

		PsiJavaCodeReferenceElement implementsReference = elementFactory.createReferenceFromText(implementsType, mClass);
		PsiReferenceList implementsList = mClass.getImplementsList();

		if (implementsList != null) {
			implementsList.add(implementsReference);
		}
	}

}
